﻿using System.Collections.Concurrent;
using XYS.Core.Models;
using XYS.Core.Util;

namespace XYS.Service.Core.Util.Helper
{
    /// <summary>
    /// 
    /// </summary>
    public static class TaskHelper
    {
        private static readonly Dictionary<string, List<Task>> TaskRunMap = new();



        /// <summary>
        /// 任务池
        /// key:任务名
        /// value:任务配置
        ///     -key：执行的任务
        ///     -value：任务最大数量
        /// </summary>
        private static readonly ConcurrentDictionary<string, KeyValueDTO<Func<int, Task>, int>> TaskPoolConfigs = new();

        /// <summary>
        /// 创建或者检查任务，如果当前任务数量小于设定的任务数量，则会自动创建任务
        /// </summary>
        /// <param name="taskName">任务名</param>
        /// <param name="maxTaskCount">任务数量</param>
        /// <param name="action">执行器</param>
        public static void CreateOrCheckLoopTask(string taskName, int maxTaskCount, Func<int, Task> action)
        {
            if (!TaskPoolConfigs.TryGetValue(taskName, out var taskConfig))
            {
                taskConfig = new KeyValueDTO<Func<int, Task>, int>()
                {
                    Key = action,
                    Value = maxTaskCount
                };
                TaskPoolConfigs[taskName] = taskConfig;
            }
            if (taskConfig.Value != maxTaskCount)
                taskConfig.Value = maxTaskCount;

            //获取当前任务
            if (!TaskRunMap.TryGetValue(taskName, out var task))
            {
                task = new List<Task>();
                TaskRunMap[taskName] = task;
            }

            if (task.Count < taskConfig.Value)
            {
                //创建任务
                for (int i = task.Count; i < taskConfig.Value; i++)
                {
                    int taskIndex = i;
                    task.Add(Task.Run(() => Actuator(taskName, taskIndex, taskConfig.Key)));
                }
            }

        }


        /// <summary>
        /// 任务执行器
        /// </summary>
        /// <param name="taskName"></param>
        /// <param name="taskIndex">任务索引</param>
        /// <param name="action"></param>
        private static void Actuator(string taskName, int taskIndex, Func<int, Task> action)
        {
            Task.Run(async () =>
            {
                while (true)
                {
                    //获取任务配置
                    var taskConfig = TaskPoolConfigs[taskName];
                    //超出任务数
                    if (taskIndex >= taskConfig.Value)
                    {
                        await Task.Delay(TimeSpan.FromSeconds(30));
                        continue;
                    }

                    //等待任务完成
                    try { await action(taskIndex); } catch { }
                    //最少需等待100毫秒
                    await Task.Delay(TimeSpan.FromMilliseconds(100));
                }
            }).DoNotAwait();
        }


        /// <summary>
        /// 任务执行器
        /// </summary>
        /// <param name="taskName"></param>
        /// <param name="taskIndex">任务索引</param>
        /// <param name="action"></param>
        private static void Actuator(string taskName, int taskIndex, Func<string, int, int, Task> action)
        {
            Task.Run(async () =>
            {
                while (true)
                {
                    //获取任务配置
                    var taskConfig = TaskPoolConfigs[taskName];
                    //超出任务数
                    if (taskIndex >= taskConfig.Value)
                    {
                        await Task.Delay(TimeSpan.FromSeconds(30));
                        continue;
                    }

                    //等待任务完成
                    try { await action(taskName, taskIndex, taskConfig.Value); } catch { }
                    //最少需等待100毫秒
                    await Task.Delay(TimeSpan.FromMilliseconds(100));
                }
            }).DoNotAwait();
        }

        /// <summary>
        /// 随机延迟
        /// </summary>
        /// <param name="min">最小</param>
        /// <param name="max">最大</param>
        /// <returns></returns>
        public static Task Delay(TimeSpan min, TimeSpan max)
        {
            TimeSpan delayTimep = DateTimeHelper.GetRandomDelay(min, max);
            return delayTimep != TimeSpan.Zero ? Task.Delay(delayTimep) : Task.CompletedTask;
        }

    }
}
